package org.az.netty_study.p09_netty组件之ByteBuf;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;

import static org.az.netty_study.ByteBufferUtil.logBuf;

/**
 * 切片，对ByteBuf进行切片，并没有产生数据复制，是浅拷贝
 * 本质还是引用了原始的ByteBuf
 * 切片是零拷贝的体现之一，因为零拷贝的思想是减少一次内存复制
 */
public class _4_slice {
    public static void main(String[] args) {
        ByteBuf buf = ByteBufAllocator.DEFAULT.buffer();
        buf.writeBytes(new byte[]{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'});
        logBuf(buf);

        /**
         * 对buf进行切片，得到buf1
         * buf1使用的还是buf里的数据(原始ByteBuf从下标0开始，往后4个字节的数据)，buf1拥有自己独立的读写指针
         */
        ByteBuf buf1 = buf.slice(0, 4);
        logBuf(buf1);
        ByteBuf buf2 = buf.slice(4, 11);
        logBuf(buf2);

        /**
         * 修改buf1下标为3的数据的值，发现buf下标为3的数据的值也变了
         * 说明buf1和buf使用的是同一块内存
         */
        buf1.setByte(3, 'z');
        logBuf(buf);

        /**
         * 由于切片是对原始ByteBuf的引用，所以不能对切片写入新数据
         * 但可以修改切片的数据
         */
        //下面代码会报错
        //buf1.writeByte(12);
        /**
         * 对原始ByteBuf进行release操作，对影响切片
         * 因为切片buf1使用的和原始ByteBuf是同一块内存，原始ByteBuf内存都被释放了，buf1肯定不能用了
         * 切片要想正常使用，在创建时应该retain(本质就是对原始ByteBuf进行retain，引用计数+1)，然后用完了在release
         */
        buf1.retain();
        //这里原始ByteBuf释放了，但buf1仍然可以使用
        buf.release();
        System.out.println(buf1.getByte(0));
        //buf1使用完了，再release
        //buf1.release();

        /**
         * duplicate
         * 如果说slice是截取的原始ByteBuf的一部分，那么duplicate则是对原始ByteBuf进行从头到尾的截取
         * 同slice一样，duplicate和原始ByteBuf使用的是同一块内存，只是duplicate拥有自己独立的读写指针
         */
        ByteBuf duplicateBuf = buf.duplicate();
        logBuf(duplicateBuf);

        /**
         * 与上面零拷贝api对立的，是一系列以copy开头的方法
         * 这些方法会复制一份新数据到新内存里，是深拷贝
         */
        ByteBuf copyBuf = buf.copy();
        copyBuf.setByte(0, 'y');
        //修改了copyBuf第一个字节的值，但是原始ByteBuf没变
        logBuf(buf);
    }
}
